package jp.wug.samples.pragprog;

import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.servlet.RequestScoped;
import com.google.inject.servlet.SessionScoped;
import jp.wug.Keys;
import jp.wug.PageFlow;
import jp.wug.Renderer;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class Store {
    Cart cart;
    EntityManager entityManager;
    boolean hasThankYouMessage;

    @Inject
    public Store(Cart cart, Entities entities) {
        this.cart = cart;
        this.entityManager = entities.get();
    }

    @Singleton
    static class EntityFactoryWrapper implements Provider<EntityManagerFactory> {
        EntityManagerFactory entityManagerFactory;

        EntityFactoryWrapper() {
            entityManagerFactory = Persistence.createEntityManagerFactory("depot");
        }

        public EntityManagerFactory get() {
            return entityManagerFactory;
        }
    }

    @RequestScoped
    static class Entities implements Provider<EntityManager> {
        EntityManager entityManager;

        @Inject
        Entities(EntityFactoryWrapper factory) {
            entityManager = factory.get().createEntityManager();
        }

        public EntityManager get() {
            return entityManager;
        }
    }

    public String getMessage() {
        return null;
    }

    public void setMessage(String message) {
        if ("thankyou".equals(message)) {
            hasThankYouMessage = true;
        }
    }

    public Cart getCart() {
        return cart;
    }

    public boolean hasThankYouMessage() {
        return hasThankYouMessage;
    }

    public Keys<Integer, ProductView> getProducts() {
        List<Integer> list = new ArrayList<Integer>();
        Query query = entityManager.createQuery("select p from ProductsEntity p");
        for (Object obj : query.getResultList()) {
            ProductsEntity p = (ProductsEntity) obj;
            list.add(p.getId());
        }
        return Keys.create(list);
    }

    public static class ProductView {
        private final static NumberFormat PRICE_FORMAT = NumberFormat.getCurrencyInstance(Locale.US);
        ProductsEntity product;
        Cart cart;

        @Inject
        ProductView(Entities entities, Cart cart, @Assisted Integer key) {
            this.cart = cart;
            product = entities.get().find(ProductsEntity.class, key);
        }

        public String getImageURL() {
            return product.getImageUrl().replace("/images/", "images/");
        }

        public String getPrice() {
            return PRICE_FORMAT.format(product.getPrice());
        }

        public ProductsEntity getProduct() {
            return product;
        }

        public ProductView getForm() {
            return this;
        }

        public void buy() {
            cart.add(product, 1);
        }
    }

    @SessionScoped
    public static class Cart {
        List<LineItemsEntity> itemList = new ArrayList<LineItemsEntity>();
        Provider<Entities> entityManagerProvider;
        Provider<PageFlow> pageFlowProvider;
        Provider<Checkout> checkoutProvider;

        @Inject
        public Cart(Provider<Entities> entityManagerProvider, Provider<PageFlow> pageFlowProvider, Provider<Checkout> checkoutProvider) {
            this.entityManagerProvider = entityManagerProvider;
            this.pageFlowProvider = pageFlowProvider;
            this.checkoutProvider = checkoutProvider;
        }

        public void renderItems(Renderer<Integer, LineItemsEntity> renderer) {
            for (LineItemsEntity item : itemList) {
                renderer.render(item.getId(), item);
            }
        }

        public LineItemsEntity getItem(Integer key) {
            EntityManager entityManager = entityManagerProvider.get().get();
            return entityManager.find(LineItemsEntity.class, key);
        }

        public String getTotalPrice() {
            BigDecimal total = new BigDecimal(0);
            for (LineItemsEntity item : itemList) {
                total = total.add(item.getTotalPrice());
            }
            return total.toString();
        }

        public Cart getForm() {
            return this;
        }

        public void checkout() {
            pageFlowProvider.get().redirectTo(Checkout.class, checkoutProvider.get());
        }

        public void clear() {
            itemList.clear();
        }

        void add(ProductsEntity product, int quantity) {
            LineItemsEntity item = new LineItemsEntity();
            item.setProduct(product);
            item.setQuantity(quantity);
            item.setTotalPrice(product.getPrice().multiply(BigDecimal.valueOf(quantity)));
            itemList.add(item);
        }
    }
}